home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 2002 Tom Parker (tom@carrott.org),
- Matthias Münch (matthias@amigaworld.de)
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- In addition, as a special exception, Tom Parker and Matthias Münch give
- permission to link the code of this program with a TCP stack of your
- choice, any official MUI libraries or classes and any custom MUI classes
- that should be necessary for the operation of this program. This
- exception also gives you permission to distribute linked combinations
- including this software with any of the before-mentioned libraries and
- classes. You must obey the GNU General Public License in all respects for
- all of the code used other than that provided by the before-mentioned
- libraries and classes. As part of this exception you are obliged to
- follow the license terms of the before-mentioned libraries, this license
- does not compel you to follow those terms, but if you do not then you may
- not link with those libraries. If you modify this file, you may extend
- this exception to your version of the file, but you are not obligated to
- do so. If you do not wish to do so, delete this exception statement from
- your version.
- */
- /*
- ** MadThreads (Easy threading with async messaging)
- */
-
- #include "madthread.h"
-
- #include <stdlib.h>
- #include <string.h>
-
- #include <proto/dos.h>
- #include <dos/dostags.h>
-
- static void mt_list_check(void);
- static void mt_list_add(mthread *t);
- static void mt_list_rem(mthread *t);
-
- u_long mt_sigmask=0;
-
- static struct MsgPort *mt_mother=NULL;
- static mthread *mt_list = NULL;
- static mthread *mt_last = NULL;
-
-
- int mt_setup(void)
- {
- mt_mother = CreateMsgPort();
- if(!mt_mother) return(0);
- mt_sigmask = (1L << (mt_mother->mp_SigBit)) | SIGBREAKF_CTRL_E;
- return 1;
- }
-
-
- void mt_cleanup(void)
- {
- mthread *t;
-
- t = mt_list;
- while(t)
- {
- Signal(t->task, SIGBREAKF_CTRL_C);
- t->handler = NULL;
- t = t->next;
- }
-
- while(1)
- {
- mt_listen();
- if(!mt_list) break;
- Wait(mt_sigmask | SIGBREAKF_CTRL_C);
- }
-
- DeleteMsgPort(mt_mother);
- mt_sigmask = 0;
- }
-
-
- void mt_listen(void)
- {
- mthread *t;
- mtmsg *m;
-
- mt_list_check();
-
- while(1)
- {
- m = (mtmsg *)GetMsg(mt_mother);
- if(!m) return;
-
- if(m->isreply)
- free(m);
- else {
- t = m->sender;
- if(t && t->handler)
- (t->handler)(t, m->com, m->data);
- m->isreply = 1;
- ReplyMsg((struct Message *)m);
- }
- }
- }
-
-
- mthread *mt_run(void (*func)(void), APTR data, mtcb handler)
- {
- mthread *t;
-
- t = malloc(sizeof(mthread));
- if(!t) return(NULL);
- memset(t, 0, sizeof(mthread));
-
- InitSemaphore(&t->lock);
- t->handler = handler;
- t->state = MT_NEW;
- t->father = FindTask(NULL);
- t->mother = mt_mother;
- t->data = data;
-
- t->task = (struct Task *)CreateNewProcTags(
- NP_Entry, (ULONG)func,
- NP_Name, (ULONG)"MadThread",
- NP_StackSize, 8192,
- TAG_DONE
- );
- if(!t->task) {
- free(t);
- return(NULL);
- }
-
- mt_list_add(t);
-
- t->task->tc_UserData = t;
- Signal(t->task, SIGF_SINGLE);
-
- return t;
- }
-
-
- void mt_message(mthread *t, int com, APTR data)
- {
- ObtainSemaphore(&t->lock);
-
- if(t->state == MT_READY) {
- mtmsg *m = malloc(sizeof(mtmsg));
- if(m) {
- memset(m, 0, sizeof(mtmsg));
- m->header.mn_ReplyPort = mt_mother;
- m->header.mn_Length = sizeof(mtmsg);
- m->com = com;
- m->data = data;
- PutMsg(t->port, (struct Message *)m);
- }
- }
-
- ReleaseSemaphore(&t->lock);
- }
-
-
- mthread *mt_start(void)
- {
- mthread *t;
- struct Task *me = FindTask(NULL);
-
- Wait(SIGF_SINGLE);
- t = (mthread *)(me->tc_UserData);
-
- ObtainSemaphore(&t->lock);
- t->port = CreateMsgPort();
- if(!t->port) {
- t->state = MT_FREE;
- ReleaseSemaphore(&t->lock);
- return(NULL);
- }
- t->state = MT_READY;
- ReleaseSemaphore(&t->lock);
-
- return t;
- }
-
-
- void mt_end(mthread *t)
- {
- ObtainSemaphore(&t->lock);
-
- t->state = MT_DONE;
- while(1) {
- mtmsg *m;
- m = (mtmsg *)GetMsg(t->port);
- if(!m) break;
- if(!m->isreply) ReplyMsg((struct Message *)m);
- }
- DeleteMsgPort(t->port);
- t->port = NULL;
-
- Forbid();
- ReleaseSemaphore(&t->lock);
- t->state = MT_FREE;
- Signal(t->father, SIGBREAKF_CTRL_E);
- }
-
-
- void mt_feedback(mthread *t, int com, APTR data)
- {
- mtmsg *m;
-
- m = malloc(sizeof(mtmsg));
- if(!m) return;
- memset(m, 0, sizeof(mtmsg));
-
- ObtainSemaphore(&t->lock);
-
- m->header.mn_ReplyPort = t->port;
- m->header.mn_Length = sizeof(mtmsg);
- m->sender = t;
- m->com = com;
- m->data = data;
- PutMsg(t->mother, (struct Message *)m);
-
- ReleaseSemaphore(&t->lock);
- }
-
-
- static void mt_list_check(void)
- {
- mthread *t, *nt;
-
- t = mt_list;
- while(t)
- {
- ObtainSemaphore(&t->lock);
- nt = t->next;
- if(t->state == MT_FREE) {
- mt_list_rem(t);
- free(t);
- } else {
- ReleaseSemaphore(&t->lock);
- }
- t = nt;
- }
- }
-
-
- static void mt_list_add(mthread *t)
- {
- if(!mt_list) mt_list=t;
- if(mt_last) {
- mt_last->next = t;
- t->prev = mt_last;
- }
- mt_last = t;
- }
-
-
- static void mt_list_rem(mthread *t)
- {
- if(mt_list == t) mt_list=t->next;
- if(t->prev) t->prev->next=t->next;
- if(t->next) t->next->prev=t->prev;
- if(mt_last == t) mt_last=t->prev;
- }
-